'use strict';
/**
 * configuration file for express.js
 * this is heavily borrow from MEAN.js with some changes on how to handle session or jwt (default)
 * change most of the app folder structure
 */

/**
 * Base Module dependencies.
 */
var fs = require('fs'),
    http = require('http'),
    https = require('https'),
    express = require('express'),
    morgan = require('morgan'),
    bodyParser = require('body-parser'),
    compression = require('compression'),
    methodOverride = require('method-override'),
    cookieParser = require('cookie-parser'),
    helmet = require('helmet'),
    passport = require('passport'),
    flash = require('connect-flash'),
    consolidate = require('consolidate'),
    path = require('path'),
    jwt = require('express-jwt');
/**
 * get our own stuff
 */
var appPath = '../app/',
    configPath = path.join(__dirname , appPath , 'config' , 'system'),
    logger = require(path.join(configPath , 'logger'));
/*
    this already call in the start so save a few loops
    config = require(path.join(configPath , 'config')),
    // new way to init the panes object
    panes = require('./panes')(config);
*/
/**
 * start express
 */
module.exports = function(config , connections)
{
    var panes = require('./panes')(config);

    // store the entire config for use later
    panes.set('config' , config);
    // Initialize express app
    var app = express();
    // store the app so we don't need to pass it to controllers / models again
    panes.set('app' , app);
    /**
    14.8.2015 - breaking change, we need to support multiple database profile.
              - we store all the connections in the panes object
    **/
    panes.set('connections' , connections);
    // Globbing model files
    var modelPaths = path.resolve( path.join(__dirname , appPath , '/server/models/**/*.js') );
    // this might cause confusion in the future
    panes.methods.getGlobbedFiles(modelPaths).forEach(function(modelPath)
    {
        // from now on we always pass the express app to the model init
        require(path.resolve(modelPath))(panes);
    });

    //////////////////////////////////////////
    // Setting application local variables  //
    //////////////////////////////////////////

    app.locals.title       = config.app.title;
    app.locals.description = config.app.description;
    app.locals.keywords    = config.app.keywords;

    app.locals.jsFiles     = config.getJavaScriptAssets();
    app.locals.cssFiles    = config.getCSSAssets();

    // Passing the request url to environment locals
    app.use(function(req, res, next) {
        res.locals.url = req.protocol + '://' + req.headers.host + req.url;
        // console.log('url' , res.locals.url);
        next();
    });

    // Should be placed before express.static
    app.use(compression({
        // only compress files for the following content types
        filter: function(req, res) {
            return (/json|text|javascript|css/).test(res.getHeader('Content-Type'));
        },
        // zlib option for compression level
        level: 3
    }));

    // Showing stack errors
    if (process.env.NODE_ENV === 'development') {
        app.set('showStackError', true);
    }
    //////////////////////////////////
    //  SETTING UP TEMPLATE ENGINEE //
    //////////////////////////////////

    // Set swig as the template engine - see: http://expressjs.com/4x/api.html#app.engine
    app.engine(config.view, consolidate[config.templateEngine]);

    // Set views path and view engine
    app.set('view engine', config.view);
    app.set('views', path.resolve( path.join(__dirname , appPath , 'server/views' ) ) );

    ///////////////////////////////////////
    // Environment dependent middleware  //
    ///////////////////////////////////////

    if (process.env.NODE_ENV === 'development') {
        // Disable views cache
        app.set('view cache', false);
    } else if (process.env.NODE_ENV === 'production') {
        // allow the user to specify their own cache method from config
        app.locals.cache = config.cache ? config.cache : 'memory';
    }

    // Request body parsing middleware should be above methodOverride
    app.use(bodyParser.urlencoded({
        extended: true
    }));
    app.use(bodyParser.json());
    app.use(methodOverride());
    // add file upload supports
    // app.use(multer());

    //////////////////////////////////////////
    // Use helmet to secure Express headers //
    //////////////////////////////////////////

    app.use(helmet.xframe());
    app.use(helmet.xssFilter());
    app.use(helmet.nosniff());
    app.use(helmet.ienoopen());
    app.disable('x-powered-by');

    ////////////////////////////////////
    // Setting the app static folder  //
    ////////////////////////////////////

    /**
     * this is one missing feature I always want to add. We should be building (with gulp) and compress all the files
     * and serving up from a different directory
     */
    var staticDir = (process.env.NODE_ENV==='production' || process.env.NODE_ENV==='secure') ? 'dist' : 'web';

    app.use(
        express.static(
            path.resolve( path.join (__dirname , appPath , 'client/' , staticDir) )
        )
    );
    // Enable logger (morgan) - we don't want to log the static files request so put it after setting the static folder
    app.use(morgan(logger.getLogFormat(), logger.getLogOptions()));
    // CookieParser should be above session - do we need this anymore?
    app.use(cookieParser());

    app.use(passport.initialize());
    // connect flash for flash messages
    app.use(flash());
      // 13.8.2015
    ////////////////////////////////////////////////
    //  using one method to route them all        //
    ////////////////////////////////////////////////
    // 14.8.2015 after thinking a bit more
    panes.router(app);

    // Assume 404 since no middleware responded
    app.use(function(req, res) {
        res.status(404).render('404', {
            url: req.originalUrl,
            error: 'Not Found'
        });
    });

    /**
     * Assume 'not found' in the error msgs is a 404.
     * this is somewhat silly, but valid, you can do whatever you like,
     * set properties, use instanceof etc.
     */
    app.use(function(err, req, res, next) {
        // If the error object doesn't exists
        if (!err) {
            return next();
        }
        // Log it
        console.error('500 error @ ' + res.locals.url  , err.stack);
        // Error page
        res.status(500).render('500', {
            error: err.stack
        });
    });

    /////////////////////////
    // SERVE UP VIA HTTPS  //
    /////////////////////////

    if (process.env.NODE_ENV === 'secure') {
        // Load SSL key and certificate
        /*
            config.ssl.key = 'config/sslcerts/key.pem'
            config.ssl.cert = 'config/sslcerts/cert.pem'
        */
        var privateKey = fs.readFileSync( path.join( __dirname , appPath , config.ssl.key) , 'utf8');
        var certificate = fs.readFileSync( path.join( __dirname , appPath , config.ssl.cert) , 'utf8');
        // Create HTTPS Server
        var httpsServer = https.createServer({
            key: privateKey,
            cert: certificate
        }, app);

        // Return HTTPS server instance
        return httpsServer;
    }

    ////////////////////////
    //  @TODO Socket.io   //
    ////////////////////////



    // Return Express server instance
    return app;
};
